package cli;

import java.io.IOException;
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.List;

import shared.*;

import cli.menu.Function;
import cli.menu.State;
import cli.tools.Tools;

import jline.console.ConsoleReader;
import jline.console.completer.ArgumentCompleter;
import jline.console.completer.Completer;
import jline.console.completer.StringsCompleter;

public class CliWJline extends CLI {
	
	private static ConsoleReader console;
	
	private static final Completer period = new StringsCompleter(new String[] {"day" , "month", "year"});
	private static final Completer subject = new StringsCompleter(new String[] {"expense","income","category", "mode" });
	
	private static final Completer expense = new StringsCompleter(new String[] {"expense"});
	
	private static List<Completer> listSet = new ArrayList<Completer>();
	private static final Completer listCommand = new StringsCompleter(new String [] {"list"});
	private static final Completer listArguments = new StringsCompleter(new String [] {"category", "mode"});
	
	//private static List<Completer> oprSet = new ArrayList<Completer>();
	//private static final Completer operations = new StringsCompleter(new String[] {"add","general","track", "exit", "list"});
	private List<Completer> generalSet = new ArrayList<Completer>();
	private static final Completer genCommand =new StringsCompleter(new String[] {"general"});
	
	
	private static Completer catList = new StringsCompleter(new String [] {"uncategorised","food", "entertainment", "utilities", "clothes"});
	private static Completer modeList = new StringsCompleter(new String [] {"uncategorised", "cash", "nets", "giro"});;

	private List<Completer> addSet = new ArrayList<Completer>();
	private static final Completer addCommand = new StringsCompleter(new String [] {"add"});
	
	private static ArgumentCompleter listArgCmp;
	private static ArgumentCompleter addArgCmp;
	private static ArgumentCompleter addInArgCmp;
	private static ArgumentCompleter trackArgCmp;
	private static ArgumentCompleter genArgCmp; 

	
	public CliWJline(){
		try {
			console = new ConsoleReader();
//			init();
		} catch (IOException e) {
			println("Failed to start CLI with Jline, aborting...");
			println("Using normal CLI instead");
			e.printStackTrace();
		}
	}
	
	private void init(){
		//grabs latest copy of mode and cat list an generates name lists for auto complete
		update();
		
		//settles list auto complete
		listSet.add(listCommand);
        listSet.add(listArguments);
        listArgCmp = new ArgumentCompleter(listSet);
        
        //settles general report auto complete
        generalSet.add(genCommand);
        generalSet.add(period);
        genArgCmp = new ArgumentCompleter(generalSet);
        
        //settles add auto complete add expense
        addSet.add(addCommand);
        addSet.add(expense);
        addSet.add(modeList);
        addSet.add(catList);
        addArgCmp = new ArgumentCompleter(addSet);
        
        
        console.addCompleter(addArgCmp);
        console.addCompleter(genArgCmp);
      	console.addCompleter(listArgCmp);
	}
	

	//method to update list of names for auto complete
	public void update(){
		ArrayList<String> categoryNames = new ArrayList<String>();
		
		//hide away Loan Payment Category
		List<Category> temp = api.getCategoryList();
		temp.remove(1);
	
		for(Category c: temp){
			categoryNames.add(c.getName().toLowerCase());
		}
	
		catList = new StringsCompleter(categoryNames);
		
		ArrayList<String>modeNames = new ArrayList<String>();
		for(Mode m: api.getModeList()){
			modeNames.add(m.getName().toLowerCase());
		}
		
		modeList = new StringsCompleter(modeNames);
		
	}
	
	
	
	@Override
	public void runUI() {
		CliWJline cli = this;
		clearScreen();
		if (debug){
			cli.println("Running platform: "
					+ System.getProperty("os.name"));
			cli.println("CLI : with Jline");
		}
		// init
		cli.println("BudgetBuoy v0.02 is loading...");		
	
		// init CLI
		try {
			api.init();
			init();
			CommandParser cmdParser = new CommandParser(this);
			Tools tools = new Tools(cli);
			//sets a static CLI to all menus (which extend Function)
			Function.initFunction(cli,tools, cmdParser);	
			cli.println("Loaded");
			cli.checkAlert();
			// println("Alerts checked");
			State current = State.MAINMENU;
			State nextState;
			
			//loop for menus
			while(true){
			nextState = current.run();
			api.save();
			current = nextState;
			}
		
		}
		catch(Exception e){
			cli.println("System experienced a point of failure:");
			cli.print(e.getMessage()+ "\n");
			e.printStackTrace();
			cli.println("Terminating...");
			
		}
		
	}
	
	
	// override input and output methods
	@Override
	public void print(String toPrint) {
		while(true){
			try{
				console.print(toPrint);
				console.flush();
				return;
			}
			catch(Exception e){
				
			}
		}
	}

	@Override
	public void clearScreen(){
		try {
			console.clearScreen();
			console.flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			
		}
		
	}
	
	@Override
	public void print(String[] toPrint) {
	
		while(true){
			try{
				for (String s : toPrint)
					console.println(s);
				console.flush();
				return;
			}
			catch(Exception e){
				
			}
		}
	}

	@Override
	public void println(String toPrint) {
		while(true){
			try{
				console.println(toPrint);
				console.flush();
				return;
			}
			catch(Exception e){
				
			}
		}
	}

	@Override
	public void println() {
		while(true){
			try{
				console.println();
				console.flush();
				return;
			}
			catch(Exception e){
				
			}
		}
	}

	//Jline does not have printf
	@Override
	public void printf(String toPrint, Object...args) {
//		console.getPrintStream().printf(toPrint, args);
		
		try{
		console.print(String.format(toPrint, args));
		console.flush();
		}
		catch(Exception e){
			e.printStackTrace();
		}
		
	}
	
	@Override
	public String nextLine() {
		String input = null;
//		while(input == null){
			try{
			input = console.readLine();;
			}
			catch(Exception e){
				
			}
			
//		}
		return input;
	}
	
	@Override
	public int nextInt() throws Exception{
		try{
	String input = console.readLine();
	Integer result = Integer.parseInt(input);
	return result;
		}
		catch(Exception e){
			throw new InputMismatchException();
		}
		
	}
	
	
	}

